package com.abel.bigwater.data.sanchuan

import com.abel.bigwater.data.BcdString
import com.abel.bigwater.model.JsonHelper
import com.alibaba.fastjson.annotation.JSONField
import io.netty.buffer.ByteBuf
import java.util.*
import kotlin.experimental.and

class MeterOnlineReply(_dataLen: Int?) : SanchuanData(_dataLen) {
    var serverTimeStr: BcdString? = null

    @JSONField(format = JsonHelper.FULL_DATE_FORMAT)
    var serverTime: Date? = null
        set(value) {
            field = value
            if (value == null) serverTimeStr = null
            else serverTimeStr = BcdString.fromSanchuanDate(value)
        }
        get() = serverTimeStr?.toSanchunDate()

    var serverState: ServerStateType? = null

    init {
        assert(dataLen == null || FIXED_LEN == dataLen)
    }

    /**
     * 计算数据长度，针对解析和打包
     */
    override fun computeDataLen(): Int {
        dataLen = FIXED_LEN

        return dataLen!!
    }

    /**
     * 从当前位置写入打包字节流
     */
    override fun fillBuffer(buf: ByteBuf) {
        if (serverTime == null) serverTime = Date()
        buf.alloc().buffer().apply {
            writeBytes(serverTimeStr!!.hexArray)

            writeByte(serverState!!.code)

            // transfer in batch.
            buf.writeBytes(this)
        }
    }

    /**
     * 解析字节流，从buf当前位置开始，并且消费其中的字节。
     */
    override fun <T : SanchuanData> parseBuffer(buf: ByteBuf): T? {
        buf.readBytes(dataLen!!).apply {
            serverTimeStr = BcdString.create(this, 7)
            serverTime = serverTimeStr!!.toSanchunDate()

            serverState = ServerStateType.findByCode(buf.readByte().toInt().and(0xFF))
        }

        return this as T
    }

    companion object {
        const val FIXED_LEN = 8
    }
}


/**
 * 服务器的状态：
0x00 服务器正常，接下来服务器将主动发送命令，水表应处于接收状态。服务器可通过此命令主动结束水表的连续上线指令，接下来由服务器主动发送数据。
0x01 服务器正常，但接下没有需要操作的指令，水表可以直接下线。
0x02 服务器正常，等待水表下一个上线指令，水表应继续处于发送状态。
0xFF为暂停服务状态，此时水表应直接下线
其它值待定义
 */
enum class ServerStateType {
    SendCommand(0),
    GameOver(1),
    WaitMeterCommand(2),
    ServicePause(0xFF);

    val code: Int

    constructor(_code: Int) {
        code = _code
    }

    companion object {
        fun findByCode(_code: Int): ServerStateType? = ServerStateType.values().find { it.code == _code }
    }
}